﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Grundy.Common;
using Grundy.Entity;
using Grundy.Message;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NSubstitute;
using System.Linq;

namespace Grundy.Licensing.Server.Tests
{
    [TestClass]
    public class LicenseSessionStoreTests
    {
        private LicenseStore licensesStore;
        private List<CustomerLicenseEntitlement> selfEntitlements;
        private CustomerLicenseEntitlement[] otherEntitlements;
        private Guid feature1Id;
        private Guid feature2Id;
        private LicensingStrategyFactory licensingStrategyFactory;

        [TestInitialize]
        public void Setup()
        {
            licensesStore = Substitute.For<LicenseStore>();
            licensingStrategyFactory = Substitute.For<LicensingStrategyFactory>();
            feature1Id = Guid.NewGuid();
            feature2Id = Guid.NewGuid();
            selfEntitlements = new List<CustomerLicenseEntitlement>
                                   {
                                       new CustomerLicenseEntitlement(Guid.Empty, string.Empty, new LicenseEntitlement{License = new UncountedFloatingLicense{Feature = new Feature{Id = feature1Id}}, Product = new Product()}, null),
                                       new CustomerLicenseEntitlement(Guid.Empty, string.Empty, new LicenseEntitlement{License =  new CountedFloatingLicense{Feature = new Feature{Id = feature2Id}}, Product = new Product()}, null)
                                   };
            otherEntitlements = new CustomerLicenseEntitlement[]
                                    {
                                        new  CustomerLicenseEntitlement(Guid.Empty, string.Empty, new LicenseEntitlement{License =  new UncountedFloatingLicense(), Product = new Product(), Node = new Node{Identifiers = new IdentifierCollection()}}, null)
                                    };
            licensesStore.SelfCustomerProductLicenseEntitlements.Returns(selfEntitlements);
            licensesStore.SelfCustomerProductLicenseEntitlements.Returns(selfEntitlements);
                                   
        }

        [TestMethod]
        [ExpectedException(typeof(LicenseNotFoundException))]
        public void Should_throw_exception_when_no_matching_licenses_are_found()
        {
            var fik = new FeatureIdentificationKey();
            var licenseSessionStore = new LicenseSessionStore(licensesStore, licensingStrategyFactory, new TimeSpan(0, 0, 30, 0));
            licenseSessionStore.Checkout(new LicenseRequestInformation{FeatureIdentificationKey = fik});
        }

        [TestMethod]
        [ExpectedException(typeof(AmbiguousLicenseException))]
        public void Should_throw_exception_when_multiple_matching_licenses_are_found()
        {
            selfEntitlements[0].License.Feature.Id = feature1Id;
            selfEntitlements[1].License.Feature.Id = feature1Id;
            var fik = new FeatureIdentificationKey{FeatureId = feature1Id};
            var licenseSessionStore = new LicenseSessionStore(licensesStore, licensingStrategyFactory, new TimeSpan(0, 0, 30, 0));
            licenseSessionStore.Checkout(new LicenseRequestInformation { FeatureIdentificationKey = fik });
        }

        [TestMethod]
        public void Should_call_checkout_of_licensing_strategy()
        {
            var sessionId = Guid.NewGuid();
            var fik = new FeatureIdentificationKey{FeatureId = feature1Id};
            var licensingStrategy = Substitute.For<ILicensingStrategy>();
            licensingStrategy.Checkout(null, null).ReturnsForAnyArgs(i => sessionId);
            licensingStrategyFactory.GetLicensingStrategyForLicense(null, LicenseEntitlementValidity.Null, null).ReturnsForAnyArgs(i => licensingStrategy);

            var licenseSessionStore = new LicenseSessionStore(licensesStore, licensingStrategyFactory, new TimeSpan(0, 0, 30, 0));
            var checkout = licenseSessionStore.Checkout(new LicenseRequestInformation { FeatureIdentificationKey = fik, ClientIdentifiers = new IdentifierCollection()});
            licensingStrategy.ReceivedWithAnyArgs().Checkout(null, null);
        }

        [TestMethod]
        public void Should_not_all_checkin_on_session_not_found()
        {
            var fik = new FeatureIdentificationKey { FeatureId = feature1Id };
            var licensingStrategy = Substitute.For<ILicensingStrategy>();
            licensingStrategy.Checkin(null, null).ReturnsForAnyArgs(i => true);
            licensingStrategyFactory.GetLicensingStrategyForLicense(null, LicenseEntitlementValidity.Null, null).ReturnsForAnyArgs(i => licensingStrategy);

            var licenseSessionStore = new LicenseSessionStore(licensesStore, licensingStrategyFactory, new TimeSpan(0, 0, 30, 0));
            var checkout = licenseSessionStore.Checkin(new LicenseRequestInformation { FeatureIdentificationKey = fik, ClientIdentifiers = new IdentifierCollection() });
            licensingStrategy.DidNotReceiveWithAnyArgs().Checkin(null, null);
        }

        [TestMethod]
        public void Should_not_reassert_session_when_session_not_found()
        {
            var fik = new FeatureIdentificationKey { FeatureId = feature1Id };
            var licensingStrategy = Substitute.For<ILicensingStrategy>();
            licensingStrategy.Reassert(Guid.Empty, null).ReturnsForAnyArgs(i => true);
            licensingStrategyFactory.GetLicensingStrategyForLicense(null, LicenseEntitlementValidity.Null, null).ReturnsForAnyArgs(i => licensingStrategy);

            var licenseSessionStore = new LicenseSessionStore(licensesStore, licensingStrategyFactory, new TimeSpan(0, 0, 30, 0));
            var checkout = licenseSessionStore.Reassert(new LicenseRequestInformation { FeatureIdentificationKey = fik, ClientIdentifiers = new IdentifierCollection() });
            licensingStrategy.DidNotReceiveWithAnyArgs().Reassert(Guid.Empty, null);
        }
    }
}